//    Openbravo POS is a point of sales application designed for touch screens.
//    Copyright (S) 2007-2009 Openbravo, S.L.
//    http://www.openbravo.com/product/pos
//
//    This file is part of Openbravo POS.
//
//    Openbravo POS is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    Openbravo POS is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with Openbravo POS.  If not, see <http://www.gnu.org/licenses/>.

package com.openbravo.data.loader.serialize;

import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.Clob;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.openbravo.data.basic.BasicException;
import e.odbo.data.util.ImageUtils;

public abstract class Datas<T> {

    public final static Datas<Integer> INT = new DatasINT();
    public final static Datas<String> STRING = new DatasSTRING();
    public final static Datas<Double> DOUBLE = new DatasDOUBLE();
    public final static Datas<Boolean> BOOLEAN = new DatasBOOLEAN();
    public final static Datas<Date> TIMESTAMP = new DatasTIMESTAMP();
    public final static Datas<byte[]> BYTES = new DatasBYTES();
    public final static Datas IMAGE = new DatasIMAGE();
    //public final static Datas INPUTSTREAM = new DatasINPUTSTREAM();
    public final static Datas OBJECT = new DatasOBJECT();
    public final static Datas SERIALIZABLE = new DatasSERIALIZABLE();
    public final static Datas NULL = new DatasNULL();

    public final static Datas OBJECTS = new DatasOBJECTS();
    public final static Datas<Long> LONG = new DatasLONG();
    public final static Datas<Short> SHORT = new DatasSHORT();
    public final static Datas<Clob> CLOB = new DatasCLOB();
    public final static Datas<Blob> BLOB = new DatasBLOB();
    public final static Datas<BigDecimal> BIGDECIMAL=new DatasBIGDECIMAL();

    private static DateFormat tsf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    /**
     * Creates a new instance of Datas
     */
    protected Datas() {
    }

    public abstract T getValue(DataRead dr, int i) throws BasicException;

    public abstract void setValue(DataWrite dw, int i, T value) throws BasicException;

    public abstract Class getClassValue();

    protected abstract String toStringAbstract(Object value);

    protected abstract int compareAbstract(Object o1, Object o2);

    public String toString(Object value) {
        if (value == null) {
            return "null";
        } else {
            return toStringAbstract(value);
        }
    }

    public int compare(Object o1, Object o2) {
        if (o1 == null) {
            if (o2 == null) {
                return 0;
            } else {
                return -1;
            }
        } else if (o2 == null) {
            return +1;
        } else {
            return compareAbstract(o1, o2);
        }
    }

    private static final class DatasINT extends Datas<Integer> {
        public Integer getValue(DataRead dr, int i) throws BasicException {
            return dr.getInt(i);
        }

        public void setValue(DataWrite dw, int i, Integer value) throws BasicException {
            dw.setInt(i, (Integer) value);
        }

        public Class getClassValue() {
            return java.lang.Integer.class;
        }

        protected String toStringAbstract(Object value) {
            return ((Integer) value).toString();
        }

        protected int compareAbstract(Object o1, Object o2) {
            return ((Integer) o1).compareTo((Integer) o2);
        }
    }

    private static final class DatasSTRING extends Datas<String> {
        public String getValue(DataRead dr, int i) throws BasicException {
            return dr.getString(i);
        }

        public void setValue(DataWrite dw, int i, String value) throws BasicException {
            dw.setString(i, (String) value);
        }

        public Class getClassValue() {
            return java.lang.String.class;
        }

        protected String toStringAbstract(Object value) {
            return "\'" + DataWriteUtils.getEscaped((String) value) + "\'";
        }

        protected int compareAbstract(Object o1, Object o2) {
            return ((String) o1).compareTo((String) o2);
        }
    }

    private static final class DatasDOUBLE extends Datas<Double> {
        public Double getValue(DataRead dr, int i) throws BasicException {
            return dr.getDouble(i);
        }

        public void setValue(DataWrite dw, int i, Double value) throws BasicException {
            dw.setDouble(i, (Double) value);
        }

        public Class getClassValue() {
            return java.lang.Double.class;
        }

        protected String toStringAbstract(Object value) {
            return ((Double) value).toString();
        }

        protected int compareAbstract(Object o1, Object o2) {
            return ((Double) o1).compareTo((Double) o2);
        }
    }

    private static final class DatasBOOLEAN extends Datas<Boolean> {
        public Boolean getValue(DataRead dr, int i) throws BasicException {
            return dr.getBoolean(i);
        }

        public void setValue(DataWrite dw, int i, Boolean value) throws BasicException {
            dw.setBoolean(i, (Boolean) value);
        }

        public Class getClassValue() {
            return java.lang.Boolean.class;
        }

        protected String toStringAbstract(Object value) {
            return ((Boolean) value).toString();
        }

        protected int compareAbstract(Object o1, Object o2) {
            return ((Boolean) o1).compareTo((Boolean) o2);
        }
    }

    private static final class DatasTIMESTAMP extends Datas<Date> {
        public Date getValue(DataRead dr, int i) throws BasicException {
            return dr.getTimestamp(i);
        }

        public void setValue(DataWrite dw, int i, Date value) throws BasicException {
            dw.setTimestamp(i, (java.util.Date) value);
        }

        public Class getClassValue() {
            return java.util.Date.class;
        }

        protected String toStringAbstract(Object value) {
            return tsf.format(value);
        }

        protected int compareAbstract(Object o1, Object o2) {
            return ((java.util.Date) o1).compareTo((java.util.Date) o2);
        }
    }

    private static final class DatasBYTES extends Datas<byte[]> {
        public byte[] getValue(DataRead dr, int i) throws BasicException {
            return dr.getBytes(i);
        }

        public void setValue(DataWrite dw, int i, byte[] value) throws BasicException {
            dw.setBytes(i, (byte[]) value);
        }

        public Class getClassValue() {
            return byte[].class;
        }

        protected String toStringAbstract(Object value) {
            return "0x" + ImageUtils.bytes2hex((byte[]) value);
        }

        protected int compareAbstract(Object o1, Object o2) {
            throw new UnsupportedOperationException();
        }
    }

    private static final class DatasIMAGE extends Datas<java.awt.image.BufferedImage> {
        public java.awt.image.BufferedImage getValue(DataRead dr, int i) throws BasicException {
            return ImageUtils.readImage(dr.getBytes(i));
        }

        public void setValue(DataWrite dw, int i, java.awt.image.BufferedImage value) throws BasicException {
            dw.setBytes(i, ImageUtils.writeImage((java.awt.image.BufferedImage) value));
        }

        public Class getClassValue() {
            return java.awt.image.BufferedImage.class;
        }

        protected String toStringAbstract(Object value) {
            return "0x" + ImageUtils.bytes2hex(ImageUtils.writeImage((java.awt.image.BufferedImage) value));
        }

        protected int compareAbstract(Object o1, Object o2) {
            throw new UnsupportedOperationException();
        }
    }

    //    private static final class DatasINPUTSTREAM extends Datas {
//        public Object getColumnName(DataRead dr, int i) throws DataException {
//            byte[] b = dr.getBytes(i);
//            return b == null ? null : new java.serializer.ByteArrayInputStream(b);
//        }
//        public void setValue(DataWrite dw, int i, Object columnName) throws DataException {
//            // TODO: Please implement this method
//        }
//    }  
    private static final class DatasOBJECT extends Datas {
        public Object getValue(DataRead dr, int i) throws BasicException {
            return dr.getObject(i);
        }

        public void setValue(DataWrite dw, int i, Object value) throws BasicException {
            dw.setObject(i, value);
        }

        public Class getClassValue() {
            return java.lang.Object.class;
        }

        protected String toStringAbstract(Object value) {
            return "0x" + ImageUtils.bytes2hex(ImageUtils.writeSerializable(value));
        }

        protected int compareAbstract(Object o1, Object o2) {
            throw new UnsupportedOperationException();
        }
    }

    private static final class DatasOBJECTS extends Datas<Object[]> {
        public Object[] getValue(DataRead dr, int i) throws BasicException {
            throw new UnsupportedOperationException();
        }

        public void setValue(DataWrite dw, int i, Object[] value) throws BasicException {
            if (dw instanceof QBFParameterDataWrite) {
                ((QBFParameterDataWrite) dw).setObjects(i, (Object[]) value);
            } else
                throw new UnsupportedOperationException();

        }

        public Class getClassValue() {
            return java.lang.Object.class;
        }

        protected String toStringAbstract(Object value) {
            throw new UnsupportedOperationException();
        }

        protected int compareAbstract(Object o1, Object o2) {
            throw new UnsupportedOperationException();
        }
    }

    private static final class DatasSERIALIZABLE extends Datas {
        public Object getValue(DataRead dr, int i) throws BasicException {
            return ImageUtils.readSerializable(dr.getBytes(i));
        }

        public void setValue(DataWrite dw, int i, Object value) throws BasicException {
            dw.setBytes(i, ImageUtils.writeSerializable(value));
        }

        public Class getClassValue() {
            return java.lang.Object.class;
        }

        protected String toStringAbstract(Object value) {
            return "0x" + ImageUtils.bytes2hex(ImageUtils.writeSerializable(value));
        }

        protected int compareAbstract(Object o1, Object o2) {
            throw new UnsupportedOperationException();
        }
    }

    private static final class DatasNULL extends Datas {
        public Object getValue(DataRead dr, int i) throws BasicException {
            return null;
        }

        public void setValue(DataWrite dw, int i, Object value) throws BasicException {
            // No asigno null, no asigno nada.
        }

        public Class getClassValue() {
            return java.lang.Object.class;
        }

        protected String toStringAbstract(Object value) {
            return "null";
        }

        protected int compareAbstract(Object o1, Object o2) {
            throw new UnsupportedOperationException();
        }
    }

    private static final class DatasLONG extends Datas<Long> {
        public Long getValue(DataRead dr, int i) throws BasicException {
            return dr.getLong(i);
        }

        public void setValue(DataWrite dw, int i, Long value) throws BasicException {
            dw.setLong(i, (Long) value);
        }

        public Class getClassValue() {
            return java.lang.Long.class;
        }

        protected String toStringAbstract(Object value) {
            return ((Long) value).toString();
        }

        protected int compareAbstract(Object o1, Object o2) {
            return ((Long) o1).compareTo((Long) o2);
        }
    }

    private static final class DatasSHORT extends Datas<Short> {
        public Short getValue(DataRead dr, int i) throws BasicException {
            return dr.getShort(i);
        }

        public void setValue(DataWrite dw, int i, Short value) throws BasicException {
            dw.setShort(i, (Short) value);
        }

        public Class getClassValue() {
            return java.lang.Short.class;
        }

        protected String toStringAbstract(Object value) {
            return ((Short) value).toString();
        }

        protected int compareAbstract(Object o1, Object o2) {
            return ((Short) o1).compareTo((Short) o2);
        }
    }

    private static final class DatasCLOB extends Datas<Clob> {
        public Clob getValue(DataRead dr, int i) throws BasicException {
            return dr.getClob(i);
        }

        public void setValue(DataWrite dw, int i, Clob value) throws BasicException {
            dw.setClob(i,  value);
        }

        public Class getClassValue() {
            return Clob.class;
        }

        protected String toStringAbstract(Object value) {
            return DataWriteUtils.getSQLValue((Clob) value);
        }

        protected int compareAbstract(Object o1, Object o2) {
            return 0;
        }
    }

    private static final class DatasBLOB extends Datas<Blob> {
        public Blob getValue(DataRead dr, int i) throws BasicException {
            return dr.getBlob(i);
        }

        public void setValue(DataWrite dw, int i, Blob value) throws BasicException {
            dw.setBlob(i,  value);
        }

        public Class getClassValue() {
            return Blob.class;
        }

        protected String toStringAbstract(Object value) {
            return DataWriteUtils.getSQLValue((Blob) value);
        }

        protected int compareAbstract(Object o1, Object o2) {
            return 0;
        }
    }

    private static final class DatasBIGDECIMAL extends Datas<BigDecimal> {
        public BigDecimal getValue(DataRead dr, int i) throws BasicException {
            return dr.getBigDecimal(i);
        }

        public void setValue(DataWrite dw, int i, BigDecimal value) throws BasicException {
            dw.setBigDecimal(i,  value);
        }

        public Class getClassValue() {
            return BigDecimal.class;
        }

        protected String toStringAbstract(Object value) {
            return ((BigDecimal) value).toString();
        }

        protected int compareAbstract(Object o1, Object o2) {
            return 0;
        }
    }


}
